/**
 * TDS PEC 4
 * Grupo 3H2M
 *
 * El paquete <code>edu.uoc.tds.pec4.server.bbdd</code> agrupa todas las clases
 * que encapsulan los objetos de acceso a datos (DAO),para realizar el acceso
 * a datos. La base de datos es PostgreSQL.
 */
package edu.uoc.tds.pec4.server.bbdd;

import edu.uoc.tds.pec4.beans.RolDTO;
import edu.uoc.tds.pec4.beans.UsuarioDTO;
import edu.uoc.tds.pec4.common.util.Constantes;
import edu.uoc.tds.pec4.server.bbdd.exceptions.DataBaseDAOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * La clase <code>UsuarioDAO</code> es el componente de software que suministra
 * una interfaz común entre la aplicación y la base de datos, relacionada con la
 * gestión de los usuarios.<br />
 * Extiende la clase <code>DataBaseDAO</code><br />
 * 
 * @author	Luis Rivas Mariño
 * @version	03/12/2011
 * @since	1.00
 * @see         edu.uoc.tds.pec4.server.bbdd.exceptions.DataBaseDAOException
 */
public class UsuarioDAO extends DataBaseDAO implements IUsuarioDAO {

    private Connection conexion;
    /**
     * Declaramos los PreparedStatement de las consultas a realizar
     * @author Luis Rivas Mariño
     */
    private PreparedStatement pstmtAltaUsuario;
    private PreparedStatement pstmtAltaCliente;
    private PreparedStatement pstmtBajaLUsuario;
    private PreparedStatement pstmtModificaUsuario;
    private PreparedStatement pstmtAltaRol;
    private PreparedStatement pstmtAltaLUsuario;
    private PreparedStatement pstmtRolUsuario;
    private PreparedStatement pstmtBajaRol;

    /**
     * Constructor de la clase, invoca al constructor de la superclase.</br >
     *
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    public UsuarioDAO() throws DataBaseDAOException {
        super();

        pstmtAltaUsuario = super.preparedStatement("INSERT INTO usuario (idUsuario,NIF,"
                + "password,nombre,apellidos,domicilio,idCiudad,cod_postal,telefono,"
                + "movil,fax,email,inactivo) VALUES(?,?,?,?,?,?,?,?,"
                + "?,?,?,?,?)");

        pstmtAltaCliente = super.preparedStatement("UPDATE usuario SET cc=? WHERE idUsuario=?");

        pstmtBajaLUsuario = super.preparedStatement("UPDATE usuario SET inactivo=1 WHERE idUsuario=?");
        
        pstmtAltaLUsuario = super.preparedStatement("UPDATE usuario SET inactivo=0 WHERE idUsuario=?");

        pstmtModificaUsuario = super.preparedStatement("UPDATE usuario SET NIF=?,password=?,"
                + "nombre=?,apellidos=?,domicilio=?,idCiudad=?,cod_postal=?,telefono=?,"
                + "movil=?,fax=?,email=?,cc=?,inactivo=?"
                + " WHERE idUsuario=?");

        pstmtAltaRol = super.preparedStatement("INSERT INTO usuariorol (idusuario, idrol) VALUES(?,?)");

        pstmtRolUsuario = super.preparedStatement("SELECT * FROM usuariorol WHERE idusuario=? AND idrol=?");

        pstmtBajaRol = super.preparedStatement("DELETE FROM usuariorol WHERE idusuario=? AND idrol=?");
        
    }


    public UsuarioDTO consultaUsuarioPorId(String id) throws DataBaseDAOException {

        UsuarioDTO usu = null;

        String sSQL = "SELECT u.idusuario, u.nif, u.password, u.nombre, u.apellidos, u.domicilio, u.idciudad,"
                + "u.cod_postal, u.telefono, u.movil, u.fax, u.email, u.cc,u.logado, u.inactivo,"
                + " c.nombre as nomciudad,pr.nombre as nomprovincia, p.nombre as nompais from usuario u "
                + "inner join ciudad c on u.idciudad=c.idciudad inner join provincia pr on c.idprovincia=pr.idprovincia "
                + "inner join pais p on pr.idpais=p.idpais where u.idusuario ='" + id + "'";
        try {

            // Nueva transacción
            super.setAutoCommit(false);

            ResultSet objRS = super.obtenerConsulta(sSQL);
            if (!objRS.next()) {
                return usu;
            } else {
                UsuarioDTO a = new UsuarioDTO();
                a.setIdUsuario(objRS.getString("idusuario"));
                a.setNIF(objRS.getString("nif"));
                a.setPassword(objRS.getString("password"));
                a.setNomUsuario(objRS.getString("nombre"));
                a.setApellidos(objRS.getString("apellidos"));
                a.setDomicilio(objRS.getString("domicilio"));
                a.setIdCiudad(objRS.getInt("idCiudad"));
                a.setCodPostal(objRS.getString("cod_postal"));
                a.setTelefono(objRS.getString("telefono"));
                a.setMovil(objRS.getString("movil"));
                a.setFax(objRS.getString("fax"));
                a.setEMail(objRS.getString("email"));
                a.setCC(objRS.getString("cc"));
                a.setLogado(objRS.getBoolean("logado"));
                a.setInactivo(objRS.getInt("inactivo"));
                a.setNomCiudad(objRS.getString("nomciudad"));
                a.setNomProvincia(objRS.getString("nomprovincia"));
                a.setNomPais(objRS.getString("nompais"));
                usu = a;
            }
        } catch (SQLException SQLe) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_CONSULTA_USUARIO
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
        return usu;
    }

    /**
     * Obtiene la lista de roles asignados a un usuario
     * @param id El identificador del usuario
     * @return roles Lista de roles asignados al usuario
     * @throws DataBaseDAOException 
     */
    public List<RolDTO> getRoles(String id) throws DataBaseDAOException {
        List<RolDTO> roles = new ArrayList<RolDTO>();
        PreparedStatement st = null;
        String sSQL = "SELECT * FROM usuariorol WHERE idusuario ='" + id + "'";
        try {
            // Nueva transacción
            super.setAutoCommit(false);

            ResultSet objRS = super.obtenerConsulta(sSQL);
            while (objRS.next()) {
                RolDTO rol = new RolDTO();
                rol.setIdRol(objRS.getInt("idrol"));
                roles.add(rol);
            }

            // Liberamos recursos
            objRS.close();
            objRS = null;

        } catch (SQLException SQLe) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_CONSULTA_ROLES_USUARIO
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
        return roles;
    }

    /**
     * Realiza el alta de un usuario en la base de datos.
     * @author Luis Rivas Mariño
     * @since 08/12/11 
     * @param usuario El usuario a dar de alta en la base de datos
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    @Override
    public void altaUsuario(UsuarioDTO usuario) throws DataBaseDAOException {

        if (usuario == null) {
            throw new DataBaseDAOException(DataBaseDAOException.USUARIO_NULO);
        }

        try {
            // Nueva transacción
            super.setAutoCommit(false);

            //Insertamos el usuario
            pstmtAltaUsuario.clearParameters();
            pstmtAltaUsuario.setString(1, usuario.getIdUsuario());
            pstmtAltaUsuario.setString(2, usuario.getNIF());
            pstmtAltaUsuario.setString(3, usuario.getPassword());
            pstmtAltaUsuario.setString(4, usuario.getNomUsuario());
            pstmtAltaUsuario.setString(5, usuario.getApellidos());
            pstmtAltaUsuario.setString(6, usuario.getDomicilio());
            pstmtAltaUsuario.setInt(7, usuario.getIdCiudad());
            pstmtAltaUsuario.setString(8, usuario.getCodPostal());
            pstmtAltaUsuario.setString(9, usuario.getTelefono());
            pstmtAltaUsuario.setString(10, usuario.getMovil());
            pstmtAltaUsuario.setString(11, usuario.getFax());
            pstmtAltaUsuario.setString(12, usuario.getEMail());
            pstmtAltaUsuario.setInt(13, usuario.getInactivo());

            pstmtAltaUsuario.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_ALTA_USUARIO
                    + Constantes.SL + SQLe.getMessage());

        } finally {
            super.setAutoCommit(true);
        }
    }

    /**
     * Inserta en el campo CC correspondiente a un usuario del tipo Cliente
     * los datos del número de cuenta corriente facilitados
     * @param idUsuario el identificador del usuario Cliente
     */
    public void ccCliente(String cc, String idUsuario) throws DataBaseDAOException {

        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Actualizamos el cc del cliente
            pstmtAltaCliente.clearParameters();

            pstmtAltaCliente.setString(1, cc);
            pstmtAltaCliente.setString(2, idUsuario);

            pstmtAltaCliente.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_ALTA_CC_CLIENTE
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
    }

    /**
     * Realiza la baja lógica de un usuario en la base de datos.
     * @param usuario El usuario a dar de baja
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    @Override
    public void bajaUsuario(String idUsuario) throws DataBaseDAOException {

        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Damos de baja lógica al usuario
            pstmtBajaLUsuario.clearParameters();
            pstmtBajaLUsuario.setString(1, idUsuario);

            pstmtBajaLUsuario.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_BAJA_USUARIO
                    + Constantes.SL + SQLe.getMessage());

        } finally {
            super.setAutoCommit(true);
        }
    }

    /**
     * Realiza el alta lógica de un usuario en la base de datos.
     * @param usuario El usuario a reactivar
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    @Override
    public void activaUsuario(String idUsuario) throws DataBaseDAOException {
 
        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Damos de baja lógica al usuario
            pstmtAltaLUsuario.clearParameters();
            pstmtAltaLUsuario.setString(1, idUsuario);

            pstmtAltaLUsuario.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_ALTALOGICA_USUARIO
                    + Constantes.SL + SQLe.getMessage());

        } finally {
            super.setAutoCommit(true);
        }       
    }    
    
    /**
     * Realiza la consulta de un usuario por NIF
     * @author Luis Rivas Mariño
     * @since 10/12/11  
     * @param   nif El nif del usuario a consultar en la base de datos
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    public UsuarioDTO consultaUsuarioPorNif(String nif) throws DataBaseDAOException {

        UsuarioDTO usuario = null;

        String sSQL = "SELECT u.idusuario, u.nif, u.password, u.nombre, u.apellidos, u.domicilio, u.idciudad,"
                + "u.cod_postal, u.telefono, u.movil, u.fax, u.email, u.cc,u.logado, u.inactivo,"
                + " c.nombre as nomciudad,pr.nombre as nomprovincia, p.nombre as nompais from usuario u "
                + "inner join ciudad c on u.idciudad=c.idciudad inner join provincia pr on c.idprovincia=pr.idprovincia "
                + "inner join pais p on pr.idpais=p.idpais where u.nif ='" + nif + "'";
        try {
            // Nueva transacción
            super.setAutoCommit(false);

            ResultSet objRS = super.obtenerConsulta(sSQL);
            if (!objRS.next()) {
                return usuario;
            } else {
                UsuarioDTO a = new UsuarioDTO();
                a.setIdUsuario(objRS.getString("idusuario"));
                a.setNIF(objRS.getString("nif"));
                a.setPassword(objRS.getString("password"));
                a.setNomUsuario(objRS.getString("nombre"));
                a.setApellidos(objRS.getString("apellidos"));
                a.setDomicilio(objRS.getString("domicilio"));
                a.setIdCiudad(objRS.getInt("idCiudad"));
                a.setCodPostal(objRS.getString("cod_postal"));
                a.setTelefono(objRS.getString("telefono"));
                a.setMovil(objRS.getString("movil"));
                a.setFax(objRS.getString("fax"));
                a.setEMail(objRS.getString("email"));
                a.setCC(objRS.getString("cc"));
                a.setLogado(objRS.getBoolean("logado"));
                a.setInactivo(objRS.getInt("inactivo"));
                a.setNomCiudad(objRS.getString("nomciudad"));
                a.setNomProvincia(objRS.getString("nomprovincia"));
                a.setNomPais(objRS.getString("nompais"));
                usuario = a;
            }
        } catch (SQLException SQLe) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_CONSULTA_USUARIO
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
        return usuario;
    }

    /**
     * Realiza la consulta de un usuario por su nombre y apellidos
     * @author Luis Rivas Mariño
     * @since 10/12/11  
     * @param   nombre El nombre del usuario a consultar en la base de datos
     * @param   apellidos Los apellidos del usuario a consultar en la base de datos      
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    public UsuarioDTO consultaUsuarioPorNombre(String nombre, String apellidos) throws DataBaseDAOException {
        UsuarioDTO usuario = null;

        String sSQL = "SELECT u.idusuario, u.nif, u.password, u.nombre, u.apellidos, u.domicilio, u.idciudad,"
                + "u.cod_postal, u.telefono, u.movil, u.fax, u.email, u.cc,u.logado, u.inactivo,"
                + " c.nombre as nomciudad,pr.nombre as nomprovincia, p.nombre as nompais from usuario u "
                + "inner join ciudad c on u.idciudad=c.idciudad inner join provincia pr on c.idprovincia=pr.idprovincia "
                + "inner join pais p on pr.idpais=p.idpais where u.nombre ='" + nombre + "' AND u.apellidos ='" + apellidos + "'";
        try {
            // Nueva transacción
            super.setAutoCommit(false);

            ResultSet objRS = super.obtenerConsulta(sSQL);
            if (!objRS.next()) {
                return usuario;
            } else {
                UsuarioDTO a = new UsuarioDTO();
                a.setIdUsuario(objRS.getString("idusuario"));
                a.setNIF(objRS.getString("nif"));
                a.setPassword(objRS.getString("password"));
                a.setNomUsuario(objRS.getString("nombre"));
                a.setApellidos(objRS.getString("apellidos"));
                a.setDomicilio(objRS.getString("domicilio"));
                a.setIdCiudad(objRS.getInt("idCiudad"));
                a.setCodPostal(objRS.getString("cod_postal"));
                a.setTelefono(objRS.getString("telefono"));
                a.setMovil(objRS.getString("movil"));
                a.setFax(objRS.getString("fax"));
                a.setEMail(objRS.getString("email"));
                a.setCC(objRS.getString("cc"));
                a.setLogado(objRS.getBoolean("logado"));
                a.setInactivo(objRS.getInt("inactivo"));
                a.setNomCiudad(objRS.getString("nomciudad"));
                a.setNomProvincia(objRS.getString("nomprovincia"));
                a.setNomPais(objRS.getString("nompais"));
                usuario = a;
            }
        } catch (SQLException SQLe) {
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_CONSULTA_USUARIO
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
        return usuario;
    }

    /**
     * Realiza la modificación de un usuario en la base de datos.
     * @author Luis Rivas Mariño
     * @since 08/12/11  
     * @param   usuario El usuario a modificar en la base de datos
     * @throws  DataBaseDAOException En caso de generarse una excepción de acceso
     *          a la base de datos se dispara al nivel superior
     */
    @Override
    public void modificaUsuario(UsuarioDTO usuario) throws DataBaseDAOException {

        if (usuario == null) {
            throw new DataBaseDAOException(DataBaseDAOException.EQUIPAMIENTO_NULO);
        }

        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Modificamos el equipamiento
            pstmtModificaUsuario.clearParameters();
            pstmtModificaUsuario.setString(1, usuario.getNIF());
            pstmtModificaUsuario.setString(2, usuario.getPassword());
            pstmtModificaUsuario.setString(3, usuario.getNomUsuario());
            pstmtModificaUsuario.setString(4, usuario.getApellidos());
            pstmtModificaUsuario.setString(5, usuario.getDomicilio());
            pstmtModificaUsuario.setInt(6, usuario.getIdCiudad());
            pstmtModificaUsuario.setString(7, usuario.getCodPostal());
            pstmtModificaUsuario.setString(8, usuario.getTelefono());
            pstmtModificaUsuario.setString(9, usuario.getMovil());
            pstmtModificaUsuario.setString(10, usuario.getFax());
            pstmtModificaUsuario.setString(11, usuario.getEMail());
            pstmtModificaUsuario.setString(12, usuario.getCC());
            pstmtModificaUsuario.setInt(13, usuario.getInactivo());
            pstmtModificaUsuario.setString(14, usuario.getIdUsuario());

            pstmtModificaUsuario.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_MODIFICACION_USUARIO
                    + Constantes.SL + SQLe.getMessage());

        } finally {
            super.setAutoCommit(true);
        }
    }

    /**
     * Asigna un rol a un usuario
     * @param idUsuario el identificador del usuario Cliente
     */
    public void usuarioRol(String idUsuario, int idRol) throws DataBaseDAOException {

        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Actualizamos el cc del cliente
            pstmtAltaRol.clearParameters();

            pstmtAltaRol.setString(1, idUsuario);
            pstmtAltaRol.setInt(2, idRol);

            pstmtAltaRol.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_ALTA_ROL
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
    }

    /**
     * Comprueba si un usuario tiene asignado un rol concreto
     * @param idUsuario El identificador del usuario
     * @param idRol El identificador del rol asignado
     * @return true  El usuario tiene asignado el rol
     *         false El usuario no tiene asignado el rol
     */
    @Override
    public boolean rolUsuario(String idUsuario, int idRol) throws DataBaseDAOException {
        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Comprobamos si el usuario tiene asignado el rol
            pstmtRolUsuario.clearParameters();

            pstmtRolUsuario.setString(1, idUsuario);
            pstmtRolUsuario.setInt(2, idRol);

            ResultSet rs = pstmtRolUsuario.executeQuery();
            super.commit();

            if (rs.next()) {
                return true;
            } else {
                return false;
            }

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_CONSULTA_ASIGNACION_ROL
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
    }

    /**
     * Desasigna un rol a un usuario
     * @param idUsuario el identificador de un usuario
     * @param idRol el identificador del rol a desasignar
     */
    public void bajaRol(String idUsuario, int idRol) throws DataBaseDAOException {

        try {
            // Nueva transacción
            super.setAutoCommit(false);

            // Actualizamos el cc del cliente
            pstmtBajaRol.clearParameters();

            pstmtBajaRol.setString(1, idUsuario);
            pstmtBajaRol.setInt(2, idRol);

            pstmtBajaRol.execute();
            super.commit();

        } catch (SQLException SQLe) {
            super.rollback();
            throw new DataBaseDAOException(DataBaseDAOException.ERROR_BAJA_ROL
                    + Constantes.SL + SQLe.getMessage());
        } finally {
            super.setAutoCommit(true);
        }
    }
     /* Llama al método de la clase padre para liberar recursos
     * @see java.lang.Object#finalize()
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }
}
